; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -passes=mldst-motion -S < %s | FileCheck %s

define internal void @sink_conflict(ptr %this.64.val, half %val1, i16 %val2, i32 %val3) align 2 {
; CHECK-LABEL: define internal void @sink_conflict
; CHECK-SAME: (ptr [[THIS_64_VAL:%.*]], half [[VAL1:%.*]], i16 [[VAL2:%.*]], i32 [[VAL3:%.*]]) align 2 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP_NOT_NOT:%.*]] = icmp eq i32 [[VAL3]], 0
; CHECK-NEXT:    br i1 [[CMP_NOT_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[TMP0:%.*]] = bitcast half [[VAL1]] to i16
; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i16 [[VAL2]] to half
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VAL2_SINK:%.*]] = phi i16 [ [[TMP0]], [[IF_THEN]] ], [ [[VAL2]], [[IF_ELSE]] ]
; CHECK-NEXT:    [[VAL1_SINK:%.*]] = phi half [ [[TMP1]], [[IF_THEN]] ], [ [[VAL1]], [[IF_ELSE]] ]
; CHECK-NEXT:    store i16 [[VAL2_SINK]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store half [[VAL1_SINK]], ptr [[TMP2]], align 2
; CHECK-NEXT:    ret void
;
entry:
  %cmp.not.not = icmp eq i32 %val3, 0
  br i1 %cmp.not.not, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  store half %val1, ptr %this.64.val, align 2
  %add.ptr.then = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store i16 %val2, ptr %add.ptr.then, align 2
  br label %if.end

if.else:                                          ; preds = %entry
  %add.ptr.else = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store half %val1, ptr %add.ptr.else, align 2
  store i16 %val2, ptr %this.64.val, align 2
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  ret void
}

define internal void @sink_volatile(ptr %this.64.val, half %val1, i16 %val2, i32 %val3) align 2 {
; CHECK-LABEL: define internal void @sink_volatile
; CHECK-SAME: (ptr [[THIS_64_VAL:%.*]], half [[VAL1:%.*]], i16 [[VAL2:%.*]], i32 [[VAL3:%.*]]) align 2 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP_NOT_NOT:%.*]] = icmp eq i32 [[VAL3]], 0
; CHECK-NEXT:    br i1 [[CMP_NOT_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    store volatile half [[VAL1]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    [[TMP0:%.*]] = bitcast i16 [[VAL2]] to half
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    store volatile i16 [[VAL2]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VAL1_SINK:%.*]] = phi half [ [[TMP0]], [[IF_THEN]] ], [ [[VAL1]], [[IF_ELSE]] ]
; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store half [[VAL1_SINK]], ptr [[TMP1]], align 2
; CHECK-NEXT:    ret void
;
entry:
  %cmp.not.not = icmp eq i32 %val3, 0
  br i1 %cmp.not.not, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  store volatile half %val1, ptr %this.64.val, align 2
  %add.ptr.then = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store i16 %val2, ptr %add.ptr.then, align 2
  br label %if.end

if.else:                                          ; preds = %entry
  %add.ptr.else = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store half %val1, ptr %add.ptr.else, align 2
  store volatile i16 %val2, ptr %this.64.val, align 2
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  ret void
}

define internal void @sink_ptr_to_int(ptr %this.64.val, ptr %val1, i64 %val2, i32 %val3) align 2 {
; CHECK-LABEL: define internal void @sink_ptr_to_int
; CHECK-SAME: (ptr [[THIS_64_VAL:%.*]], ptr [[VAL1:%.*]], i64 [[VAL2:%.*]], i32 [[VAL3:%.*]]) align 2 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP_NOT_NOT:%.*]] = icmp eq i32 [[VAL3]], 0
; CHECK-NEXT:    br i1 [[CMP_NOT_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[VAL1]] to i64
; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[VAL2]] to ptr
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VAL2_SINK:%.*]] = phi i64 [ [[TMP0]], [[IF_THEN]] ], [ [[VAL2]], [[IF_ELSE]] ]
; CHECK-NEXT:    [[VAL1_SINK:%.*]] = phi ptr [ [[TMP1]], [[IF_THEN]] ], [ [[VAL1]], [[IF_ELSE]] ]
; CHECK-NEXT:    store i64 [[VAL2_SINK]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store ptr [[VAL1_SINK]], ptr [[TMP2]], align 2
; CHECK-NEXT:    ret void
;
entry:
  %cmp.not.not = icmp eq i32 %val3, 0
  br i1 %cmp.not.not, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  store ptr %val1, ptr %this.64.val, align 2
  %add.ptr.then = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store i64 %val2, ptr %add.ptr.then, align 2
  br label %if.end

if.else:                                          ; preds = %entry
  %add.ptr.else = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store ptr %val1, ptr %add.ptr.else, align 2
  store i64 %val2, ptr %this.64.val, align 2
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  ret void
}



define internal void @sink_not_castable(ptr %this.64.val, {i32, i32} %val1, i64 %val2, i32 %val3) align 2 {
; CHECK-LABEL: define internal void @sink_not_castable
; CHECK-SAME: (ptr [[THIS_64_VAL:%.*]], { i32, i32 } [[VAL1:%.*]], i64 [[VAL2:%.*]], i32 [[VAL3:%.*]]) align 2 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP_NOT_NOT:%.*]] = icmp eq i32 [[VAL3]], 0
; CHECK-NEXT:    br i1 [[CMP_NOT_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    store { i32, i32 } [[VAL1]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    [[ADD_PTR_THEN:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store i64 [[VAL2]], ptr [[ADD_PTR_THEN]], align 2
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[ADD_PTR_ELSE:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store { i32, i32 } [[VAL1]], ptr [[ADD_PTR_ELSE]], align 2
; CHECK-NEXT:    store i64 [[VAL2]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret void
;
entry:
  %cmp.not.not = icmp eq i32 %val3, 0
  br i1 %cmp.not.not, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  store {i32, i32} %val1, ptr %this.64.val, align 2
  %add.ptr.then = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store i64 %val2, ptr %add.ptr.then, align 2
  br label %if.end

if.else:                                          ; preds = %entry
  %add.ptr.else = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store {i32, i32} %val1, ptr %add.ptr.else, align 2
  store i64 %val2, ptr %this.64.val, align 2
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  ret void
}

define internal void @sink_addrspace(ptr %this.64.val, ptr %val1, ptr addrspace(1) %val2, i32 %val3) align 2 {
; CHECK-LABEL: define internal void @sink_addrspace
; CHECK-SAME: (ptr [[THIS_64_VAL:%.*]], ptr [[VAL1:%.*]], ptr addrspace(1) [[VAL2:%.*]], i32 [[VAL3:%.*]]) align 2 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP_NOT_NOT:%.*]] = icmp eq i32 [[VAL3]], 0
; CHECK-NEXT:    br i1 [[CMP_NOT_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    store ptr [[VAL1]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    [[ADD_PTR_THEN:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store ptr addrspace(1) [[VAL2]], ptr [[ADD_PTR_THEN]], align 2
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[ADD_PTR_ELSE:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store ptr [[VAL1]], ptr [[ADD_PTR_ELSE]], align 2
; CHECK-NEXT:    store ptr addrspace(1) [[VAL2]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret void
;
entry:
  %cmp.not.not = icmp eq i32 %val3, 0
  br i1 %cmp.not.not, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  store ptr %val1, ptr %this.64.val, align 2
  %add.ptr.then = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store ptr addrspace(1) %val2, ptr %add.ptr.then, align 2
  br label %if.end

if.else:                                          ; preds = %entry
  %add.ptr.else = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store ptr %val1, ptr %add.ptr.else, align 2
  store ptr addrspace(1) %val2, ptr %this.64.val, align 2
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  ret void
}


define internal void @sink_addrspace2(ptr %this.64.val, ptr addrspace(1) %val1, ptr addrspace(1) %val2, i32 %val3) align 2 {
; CHECK-LABEL: define internal void @sink_addrspace2
; CHECK-SAME: (ptr [[THIS_64_VAL:%.*]], ptr addrspace(1) [[VAL1:%.*]], ptr addrspace(1) [[VAL2:%.*]], i32 [[VAL3:%.*]]) align 2 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP_NOT_NOT:%.*]] = icmp eq i32 [[VAL3]], 0
; CHECK-NEXT:    br i1 [[CMP_NOT_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VAL2_SINK:%.*]] = phi ptr addrspace(1) [ [[VAL1]], [[IF_THEN]] ], [ [[VAL2]], [[IF_ELSE]] ]
; CHECK-NEXT:    [[VAL1_SINK:%.*]] = phi ptr addrspace(1) [ [[VAL2]], [[IF_THEN]] ], [ [[VAL1]], [[IF_ELSE]] ]
; CHECK-NEXT:    store ptr addrspace(1) [[VAL2_SINK]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store ptr addrspace(1) [[VAL1_SINK]], ptr [[TMP0]], align 2
; CHECK-NEXT:    ret void
;
entry:
  %cmp.not.not = icmp eq i32 %val3, 0
  br i1 %cmp.not.not, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  store ptr addrspace(1) %val1, ptr %this.64.val, align 2
  %add.ptr.then = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store ptr addrspace(1) %val2, ptr %add.ptr.then, align 2
  br label %if.end

if.else:                                          ; preds = %entry
  %add.ptr.else = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store ptr addrspace(1) %val1, ptr %add.ptr.else, align 2
  store ptr addrspace(1) %val2, ptr %this.64.val, align 2
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  ret void
}

define internal void @sink_addrspace3(ptr %this.64.val, half %val1, i16 %val2, i32 %val3) align 2 {
; CHECK-LABEL: define internal void @sink_addrspace3
; CHECK-SAME: (ptr [[THIS_64_VAL:%.*]], half [[VAL1:%.*]], i16 [[VAL2:%.*]], i32 [[VAL3:%.*]]) align 2 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[THIS_AS_CASTED:%.*]] = addrspacecast ptr [[THIS_64_VAL]] to ptr addrspace(1)
; CHECK-NEXT:    [[CMP_NOT_NOT:%.*]] = icmp eq i32 [[VAL3]], 0
; CHECK-NEXT:    br i1 [[CMP_NOT_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    store half [[VAL1]], ptr addrspace(1) [[THIS_AS_CASTED]], align 2
; CHECK-NEXT:    [[TMP0:%.*]] = bitcast i16 [[VAL2]] to half
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    store i16 [[VAL2]], ptr [[THIS_64_VAL]], align 2
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[VAL1_SINK:%.*]] = phi half [ [[TMP0]], [[IF_THEN]] ], [ [[VAL1]], [[IF_ELSE]] ]
; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[THIS_64_VAL]], i64 16
; CHECK-NEXT:    store half [[VAL1_SINK]], ptr [[TMP1]], align 2
; CHECK-NEXT:    ret void
;
entry:
  %this.as.casted = addrspacecast ptr %this.64.val to ptr addrspace(1)
  %cmp.not.not = icmp eq i32 %val3, 0
  br i1 %cmp.not.not, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  store half %val1, ptr addrspace(1) %this.as.casted, align 2
  %add.ptr.then = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store i16 %val2, ptr %add.ptr.then, align 2
  br label %if.end

if.else:                                          ; preds = %entry
  %add.ptr.else = getelementptr inbounds i8, ptr %this.64.val, i64 16
  store half %val1, ptr %add.ptr.else, align 2
  store i16 %val2, ptr %this.64.val, align 2
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  ret void
}
